package com.lab.net;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

/**
 * ServerSocket会堵塞, 每次只能处理一个线程. 使用多线程可以解决问题, 但是存在线程开销问题. 
 * 最佳解决方案使用NIO.
 * 
 * @author nickevin@gmail.com
 *
 */
public class Server {

	public static void main(String[] args) throws Exception {
		ServerSocket server = new ServerSocket(9090);
		Map<String, Socket> map = new HashMap<String, Socket>();
		while (true) {
			Socket client = server.accept();
			Thread threadMachine = new ServerThread(client, map);
			threadMachine.start();
		}
	}
}

class ServerThread extends Thread {

	Socket s;
	Socket temp;

	String client;
	String self;;
	String who;
	String msg;
	Map<String, Socket> map;

	public ServerThread(Socket s, Map<String, Socket> map) {
		this.s = s;
		this.map = map;
	}

	@Override
	public void run() {
		try {
			BufferedReader in = new BufferedReader(new InputStreamReader(s
					.getInputStream()));

			// 接收客户端信息
			String session;
			while ((session = in.readLine()) != null) {
				// 将信息发送到下拉菜单
				if (session.contains(":client")) {
					StringTokenizer st = new StringTokenizer(session, ":");
					client = st.nextToken();
					map.put(client, s);
					System.out.println(client + "进来了");
					/*
					 * if(clientName.equals(key)){ Socket temp=map.get(clientName); for(Socket s:map.values()){ out.println(key + ":client"); out.flush(); } } }
					 */
					for (Socket s : map.values()) {
						PrintWriter out = new PrintWriter(s.getOutputStream());
						for (String key : map.keySet()) {
							// 将客户端的名字添加到除自己以外的其他客户端
							if (client.equals(key)) {
								// 保存自己的socket
								temp = map.get(client);
								for (Socket s2 : map.values()) {
									// 将自己的名字发送给其他客户端
									if (s2 != temp) {
										PrintWriter out2 = new PrintWriter(s2
												.getOutputStream());
										out2.println(key + ":client");
										out2.flush();
									}
								}
							} else {
								// 将其他人的名字添加到当前客户端
								for (Socket s2 : map.values()) {
									if (s2 == temp) {
										PrintWriter out2 = new PrintWriter(s2
												.getOutputStream());
										out2.println(key + ":client");
										out2.flush();
									}
								}
							}
						}
						// 发送欢迎语句
						out.println(client + ":welcome");
						out.flush();
					}
				} else if (session.contains("*")) {
					StringTokenizer st = new StringTokenizer(session, "*");
					self = st.nextToken();
					who = st.nextToken();
					msg = st.nextToken();
					if (who.equals("所有人")) {
						for (Socket s : map.values()) {
							PrintWriter out = new PrintWriter(s
									.getOutputStream());
							// 发送给每一个用户
							out.println(self + "对所有人说:" + msg);
							out.flush();
						}
					} // 发送者与接收者相同
					// else if (who.equals(self)) {
					// OutputStream os = map.get(self).getOutputStream();
					// PrintWriter out = new PrintWriter(os);
					// out.println(self + "自言自语道:" + info);
					// System.out.println(self + "自言自语道:" + info);
					// out.flush();
					//
					// }
					else {
						OutputStream os = map.get(self).getOutputStream();
						PrintWriter out = new PrintWriter(os);
						OutputStream os2 = map.get(who).getOutputStream();
						PrintWriter out2 = new PrintWriter(os2);
						out.println(self + "对" + who + "说:" + msg);
						out.flush();
						out2.println(self + "对" + who + "说:" + msg);
						out2.flush();
						System.out.println(self + "对" + who + "说:" + msg);
					}
				}
			}
		} catch (IOException e) {
		} finally {
			// =======================用户离开=======================
			try {
				String temp = client;
				map.remove(client);
				for (Socket s : map.values()) {
					OutputStream os = s.getOutputStream();
					PrintWriter out = new PrintWriter(os);
					out.println(temp + "离开了");
					out.println(temp + ":quit");
					out.flush();
				}
				System.out.println(temp + "离开了");
			} catch (IOException e1) {
				e1.printStackTrace();
			}
			try {
				s.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}